﻿using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geometry;
using System;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Geodatabase;
using System.Windows.Forms;
using System.Collections.Generic;

using stdole;
using PlanningGIS.ArcGIS;

namespace PlanningGIS.Framework
{
    /// <summary>
    /// 
    /// </summary>
    public delegate void EditStateChanged();
    /// <summary>
    /// 
    /// </summary>
    internal class EditorClass : IEditor, ISnapEnvironment, IEditLayers
    {
       /// <summary>
       /// 
       /// </summary>
        private EditStateChanged m_ChangeEditState;
        /// <summary>
        /// 
        /// </summary>
        public EditStateChanged ChangeEditState
        {
            set
            {
                m_ChangeEditState = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private IEditTask m_CurrentTask;
        /// <summary>
        /// 
        /// </summary>
        public IEditTask CurrentTask { get { return m_CurrentTask; } set { m_CurrentTask = value; } }

        public IScreenDisplay Display { get { return (m_Application.Document as IMxDocument).ActiveView.ScreenDisplay; } }
        /// <summary>
        /// 
        /// </summary>
        public IEnumFeature EditSelection { get { return Map.FeatureSelection as IEnumFeature; } }
        /// <summary>
        /// 
        /// </summary>
        private esriEditState m_EditState= esriEditState.esriStateNotEditing;
        /// <summary>
        /// 
        /// </summary>
        public esriEditState EditState { get { return m_EditState; } }
        /// <summary>
        /// 
        /// </summary>
        private IWorkspace m_EditWorkspace;
        /// <summary>
        /// 
        /// </summary>
        public IWorkspace EditWorkspace { get { return m_EditWorkspace; } }

        /// <summary>
        /// 
        /// </summary>
        private IPoint m_Location = null;
        /// <summary>
        /// 
        /// </summary>
        public IPoint Location { get { return m_Location; } }

        public IMap Map { get { return (m_Application.Document as IMxDocument).FocusMap; } }
        /// <summary>
        /// 
        /// </summary>
        private IWorkspace m_ScratchWorkspace = null;
        /// <summary>
        /// 
        /// </summary>
        public IWorkspace ScratchWorkspace { get { return m_ScratchWorkspace; } }
        /// <summary>
        /// 
        /// </summary>
        private IAnchorPoint m_SelectionAnchor = null;
        /// <summary>
        /// 
        /// </summary>
        public IAnchorPoint SelectionAnchor { get { return m_SelectionAnchor; } }
        /// <summary>
        /// 
        /// </summary>
        public int SelectionCount { get { return this.Map.SelectionCount; } }
        /// <summary>
        /// 
        /// </summary>
        private IApplication m_Application = null;
        /// <summary>
        /// 
        /// </summary>
        public IApplication Parent { set { m_Application = value; } }
        private ITextElement m_TextElement;
        /// <summary>
        /// 
        /// </summary>
        public ITextElement TextElement
        {
            get
            {
                return m_TextElement;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public EditorClass()
        {
            StdFont pFont = new StdFont();
            pFont.Bold = false;
            pFont.Italic = false;
            pFont.Underline = false;
            pFont.Name = "宋体";
            pFont.Size = 8;
            m_TextElement = (ITextElement)new TextElement();
            IElement pElement = (IElement)m_TextElement;
            m_TextElement.Text = "文本";
            IFormattedTextSymbol pTextSymbol = new TextSymbol();
            pTextSymbol.Font = (IFontDisp)pFont;
            pTextSymbol.HorizontalAlignment = esriTextHorizontalAlignment.esriTHACenter;
            pTextSymbol.VerticalAlignment = esriTextVerticalAlignment.esriTVABottom;
            pTextSymbol.Angle = 0;
            //pTextSymbol.Color = ESRI.ArcGIS.ADF.Converter.ToRGBColor(dropDownColor1.MyColor);
            m_TextElement.Symbol = pTextSymbol;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public IGeometry CreateSearchShape(IPoint point)
        {
            return null;
        }

        //public void DelayEvents(bool delay)
        //{
           
        //}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="enabled"></param>
        public void EnableUndoRedo(bool enabled)
        {
            if (enabled)
                (m_EditWorkspace as IWorkspaceEdit).EnableUndoRedo();
            else
                (m_EditWorkspace as IWorkspaceEdit).DisableUndoRedo();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public IEditTask get_Task(int index)
        {
            return null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool HasEdits()
        {
            bool pHasEdits = false ;
            (m_EditWorkspace as IWorkspaceEdit).HasEdits(ref pHasEdits);
            return pHasEdits;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public IEnumFeature SearchSelection(IPoint point)
        {
            return null;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="workspace"></param>
        public void StartEditing(IWorkspace workspace)
        {
            m_EditWorkspace = workspace;
            (m_EditWorkspace as IWorkspaceEdit).StartEditing(true);
            m_EditState = esriEditState.esriStateEditing;
            List<IFeatureLayer> pLayerList = GetLayerListFromSameWorkspace();
            for (int i = 0; i < pLayerList.Count; i++)
            {
                IFeatureSnapAgent pSnapAgent = new FeatureSnapClass(this.m_Application);
                pSnapAgent.FeatureClass = pLayerList[i].FeatureClass;
                pSnapAgent.Name = pLayerList[i].Name;
                pSnapAgent.HitType = esriGeometryHitPartType.esriGeometryPartNone;
                this.AddSnapAgent(pSnapAgent);
            }
            m_ChangeEditState.Invoke();

        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        private  List<IFeatureLayer> GetLayerListFromSameWorkspace()
        {
            List<IFeatureLayer> pLayerList = new List<IFeatureLayer>();
            IList<IFeatureLayer> pFeatureLayers = MapHelper.GetAllLayer<IFeatureLayer>(this.Map);
            IEnumerator<IFeatureLayer>  pEnum = pFeatureLayers.GetEnumerator();
            pEnum.Reset();
            while (pEnum.MoveNext())
            {
                IFeatureLayer pFeatureLayer = pEnum.Current as IFeatureLayer;
                if (pFeatureLayer == null || pFeatureLayer.Valid == false)
                    continue;
                IFeatureClass pFeatureClass = pFeatureLayer.FeatureClass;
                IDataset pDataset = (IDataset)pFeatureClass;
                if (pDataset.Workspace == m_EditWorkspace) 
                    pLayerList.Add(pFeatureLayer);
            }
            return pLayerList;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="saveChanges"></param>
        public void StopEditing(bool saveChanges)
        {
            try
            {
                IWorkspaceEdit m_WorkspaceEdit = m_EditWorkspace as IWorkspaceEdit;
                if (m_WorkspaceEdit == null)
                    return;

                if (HasEdits() & HasUndos())
                {
                    DialogResult result = MessageBox.Show("当前工作空间要素已被编辑，是否保存编辑？", "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);

                    if (result == DialogResult.Yes)
                    {
                        if (m_WorkspaceEdit is IVersionEdit4) //如果有编辑冲突就放弃对冲突的要素的编辑
                        {
                            IVersionEdit4 versionEdit = (IVersionEdit4)m_WorkspaceEdit;
                            if (versionEdit != null)
                            {
                                ESRI.ArcGIS.esriSystem.IPropertySet pProSet = ((IWorkspace)m_WorkspaceEdit).ConnectionProperties;
                                string strVersion = pProSet.GetProperty("version").ToString();
                                bool Success = versionEdit.Reconcile(strVersion);
                                IEnumConflictClass enumConflictClass = versionEdit.ConflictClasses;
                                enumConflictClass.Reset();
                                IConflictClass conflictClass = enumConflictClass.Next();
                                while (conflictClass != null)
                                {
                                    IDataset dataset = (IDataset)conflictClass;
                                    if (conflictClass.HasConflicts)
                                    {
                                        versionEdit.Reconcile(strVersion);
                                        break;
                                    }
                                    conflictClass = enumConflictClass.Next();
                                }
                            }
                        }
                        m_WorkspaceEdit.StopEditing(true);
                    }
                    else if (result == DialogResult.No)
                    {
                        m_WorkspaceEdit.AbortEditOperation(); //忽略编辑操作
                        m_WorkspaceEdit.StopEditing(false);
                    }
                    else
                    {
                        return;
                    }
                }
                else
                {
                    m_WorkspaceEdit.StopEditing(false); //依然要停止编辑
                }
                m_EditState = esriEditState.esriStateNotEditing;               
                m_ChangeEditState.Invoke();
                ClearSnapAgents();
                m_EditWorkspace = null; //此时应该彻底的关闭工作空间
                return;
            }
            catch 
            {
                return;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="menuText"></param>
        public void StopOperation(string menuText)
        {
            (m_EditWorkspace as IWorkspaceEdit).StopEditOperation();
        }
        /// <summary>
        /// 
        /// </summary>
        public void StartOperation()
        {
            (m_EditWorkspace as IWorkspaceEdit).StartEditOperation();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool HasUndos()
        {
            bool bHasUndo = true;
            (m_EditWorkspace as IWorkspaceEdit).HasUndos(ref bHasUndo);
            return bHasUndo;
        }
        /// <summary>
        /// 
        /// </summary>
        public void UndoOperation()
        {
            if (HasUndos())
            {
                (m_EditWorkspace as IWorkspaceEdit).UndoEditOperation();
                IActiveView pAcitveView = (m_Application.Document as IMxDocument).ActiveView;
                pAcitveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection | esriViewDrawPhase.esriViewGeography | esriViewDrawPhase.esriViewBackground | esriViewDrawPhase.esriViewForeground | esriViewDrawPhase.esriViewGraphics | esriViewDrawPhase.esriViewGraphicSelection
                    , null, pAcitveView.Extent);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool HasRedos()
        {  bool bHasRedo = true;
            (m_EditWorkspace as IWorkspaceEdit).HasRedos(ref bHasRedo);
            return bHasRedo;
        }
        /// <summary>
        /// 
        /// </summary>
        public void RedoOperation()
        {
            if (HasRedos())
            {
                (m_EditWorkspace as IWorkspaceEdit).RedoEditOperation();
                IActiveView pAcitveView = (m_Application.Document as IMxDocument).ActiveView;
                pAcitveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection | esriViewDrawPhase.esriViewGeography | esriViewDrawPhase.esriViewBackground | esriViewDrawPhase.esriViewForeground | esriViewDrawPhase.esriViewGraphics | esriViewDrawPhase.esriViewGraphicSelection
                    , null, pAcitveView.Extent);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public void AbortOperation()
        {
            (m_EditWorkspace as IWorkspaceEdit).AbortEditOperation();
        }
        /// <summary>
        /// 
        /// </summary>
        public void SaveEditing()
        {
            IWorkspaceEdit m_WorkspaceEdit = null;
            try
            {
                m_WorkspaceEdit = m_EditWorkspace as IWorkspaceEdit;
                if (m_WorkspaceEdit != null)
                {
                    if (m_WorkspaceEdit is IVersionEdit4)
                    {
                        IVersionEdit4 versionEdit = (IVersionEdit4)m_WorkspaceEdit;
                        if (versionEdit != null)
                        {
                            ESRI.ArcGIS.esriSystem.IPropertySet pProSet = ((IWorkspace)m_WorkspaceEdit).ConnectionProperties;
                            string strVersion = pProSet.GetProperty("version").ToString();
                            bool Success = versionEdit.Reconcile(strVersion);
                            IEnumConflictClass enumConflictClass = versionEdit.ConflictClasses;
                            enumConflictClass.Reset();
                            IConflictClass conflictClass = enumConflictClass.Next();
                            while (conflictClass != null)
                            {
                                IDataset dataset = (IDataset)conflictClass;
                                if (conflictClass.HasConflicts)
                                {
                                    versionEdit.Reconcile(strVersion);
                                    break;
                                }
                                conflictClass = enumConflictClass.Next();
                            }
                        }
                    }
                    m_WorkspaceEdit.StopEditing(true);
                    m_WorkspaceEdit.StartEditing(true);
                    MessageBox.Show("保存编辑成功！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                m_WorkspaceEdit = null;
            }
            catch (Exception ex)
            {
                System.Diagnostics.Trace.TraceError("\n 保存编辑操作异常:" + ex.ToString());
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public int SnapAgentCount { get { return m_SnapAgenList.Count; } }

        private double m_SnapTolerance=7.0;
        /// <summary>
        /// 
        /// </summary>
        public double SnapTolerance { get { return m_SnapTolerance; } set { m_SnapTolerance = value; } }

        private esriSnapToleranceUnits m_SnapToleranceUnits= esriSnapToleranceUnits.esriSnapTolerancePixels;
        /// <summary>
        /// 
        /// </summary>
        public esriSnapToleranceUnits SnapToleranceUnits { get { return m_SnapToleranceUnits; } set { m_SnapToleranceUnits = value; } }
       
        private IList<ISnapAgent> m_SnapAgenList= new List<ISnapAgent>();
        /// <summary>
        /// 
        /// </summary>
        /// <param name="SnapAgent"></param>
        public void AddSnapAgent(ISnapAgent SnapAgent)
        {
            m_SnapAgenList.Add(SnapAgent);
        }
        /// <summary>
        /// 
        /// </summary>
        public void ClearSnapAgents()
        {
            m_SnapAgenList.Clear();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public ISnapAgent get_SnapAgent(int index)
        {
            return m_SnapAgenList[index];
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        public void RemoveSnapAgent(int index)
        {
            m_SnapAgenList.RemoveAt(index);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="inPoint"></param>
        /// <returns></returns>
        public IPoint SnapPoint(IPoint inPoint)
        {
            double minDistance = double.MaxValue;
            double distance = 0;
            IPoint outPoint = null;
            IPoint nearestPnt = inPoint;
            for (int i = 0; i < m_SnapAgenList.Count; i++)
            {
                ISnapAgent m_SnapAgent = m_SnapAgenList[i];
                if (m_SnapAgent.Snap(inPoint, out outPoint, this.SnapTolerance, ref distance))
                {
                    if ((distance > 0) && (distance < minDistance))
                    {
                        nearestPnt = outPoint;
                        minDistance = distance;
                    } 
                }
            }
            return nearestPnt;
        }

        private IFeatureLayer m_CurrentLayer = null;
        /// <summary>
        /// 
        /// </summary>
        public IFeatureLayer CurrentLayer { get { return m_CurrentLayer; } }

        private int m_CurrentSubtype;
        /// <summary>
        /// 
        /// </summary>
        public int CurrentSubtype { get { return m_CurrentSubtype; } }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="layer"></param>
        /// <returns></returns>
        public bool IsEditable(IFeatureLayer layer)
        {
            return (layer.FeatureClass as IDataset).Workspace.ConnectionProperties.Equals(this.EditWorkspace) ? true : false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="layer"></param>
        /// <param name="subtype"></param>
        public void SetCurrentLayer(IFeatureLayer layer, int subtype)
        {
            m_CurrentLayer = layer;
            m_CurrentSubtype = subtype;
        }

    }
}
